package com.corpgovernment.travelstandard.impl;

import com.corpgovernment.api.applytrip.apply.sync.StandardAmountSyncRequest;
import com.corpgovernment.api.applytrip.apply.sync.StandardReserveSyncRequest;
import com.corpgovernment.api.applytrip.apply.sync.StandardReserveTypeSyncRequest;
import com.corpgovernment.api.applytrip.soa.response.QueryApplyTripStandardResponse;
import com.corpgovernment.api.travelstandard.enums.FlightSwitchEnum;
import com.corpgovernment.api.travelstandard.vo.*;
import com.corpgovernment.client.ManagementClientUtil;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.enums.ClazzEnum;
import com.corpgovernment.common.enums.SwitchEnum;
import com.corpgovernment.common.utils.Null;
import com.corpgovernment.constants.TravelStandardOwnerTypeEnum;
import com.corpgovernment.dto.travelstandard.request.GetTravelStandardByTokenRequest;
import com.corpgovernment.dto.travelstandard.response.ExceedReasonVO;
import com.corpgovernment.dto.travelstandard.response.TravelStandardResponse;
import com.corpgovernment.dto.travelstandard.response.TravelStandardRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.*;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.Conditional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zl.cui
 * @date 2024/3/5
 */
@Component
@Slf4j
public class TravelStandardTokenService {
    @Autowired
    private ManagementClientUtil managementClientUtil;
    public QueryApplyTripStandardResponse getFlightApplyTripStandard(String token) {
        GetTravelStandardByTokenRequest request = new GetTravelStandardByTokenRequest();
        request.setTokenList(Collections.singletonList(token));
        List<TravelStandardResponse> travelStandardResponseList = managementClientUtil.getTravelStandardByToken(request);
        if (CollectionUtils.isEmpty(travelStandardResponseList)){
            return null;
        }
        travelStandardResponseList = travelStandardResponseList.stream().filter(t->t.getTravelStandardToken().getOwnerType() == 3).collect(Collectors.toList());
        RuleChainVO ruleChainVO = travelStandardResponseList.stream().findFirst().map(TravelStandardResponse::getRuleChain).orElse(null);
        if(ruleChainVO == null){
            return null;
        }
        if (travelStandardResponseList.get(0).getTravelStandardToken().getOwnerType() != 3){
            return null;
        }
        List<TravelStandardRuleVO>  ruleList = ruleChainVO.getRuleList();
        QueryApplyTripStandardResponse queryApplyTripStandardResponse = new QueryApplyTripStandardResponse();
        PriceRuleVO priceRuleVO = (PriceRuleVO) ruleList.stream().filter(t -> "PriceRule".equals(t.getName())).findFirst().orElse(null);
        ReserveRuleVO reserveRuleVO = (ReserveRuleVO) ruleList.stream().filter(t -> "ReserveRule".equals(t.getName())).findFirst().orElse(null);
        if (priceRuleVO == null && reserveRuleVO == null){
            queryApplyTripStandardResponse.setEnable(false);
            return queryApplyTripStandardResponse;
        }

        BigDecimal price = Optional.ofNullable(priceRuleVO).map(PriceRuleVO::getMaxPrice).orElse(null);
        if (reserveRuleVO != null && reserveRuleVO.getReserves() == null && price != null && BigDecimal.ZERO.compareTo(price) == 0){
            queryApplyTripStandardResponse.setUnLimitedType("ALL");
            List<StandardReserveTypeSyncRequest> reserveTypeList = reserveRuleVO.getReserves().entrySet().stream().map(t->{
                StandardReserveTypeSyncRequest standardReserveTypeSyncRequest = new StandardReserveTypeSyncRequest();
                standardReserveTypeSyncRequest.setReserveCode(t.getKey());
                standardReserveTypeSyncRequest.setReserveName(t.getValue());
                return standardReserveTypeSyncRequest;
            }).collect(Collectors.toList());
            StandardReserveSyncRequest reserveSyncRequest = new StandardReserveSyncRequest();
            reserveSyncRequest.setReserveTypeList(reserveTypeList);
            reserveSyncRequest.setControlType(String.join(",",reserveRuleVO.getRejectTypes()));
            queryApplyTripStandardResponse.setStandardReserve(reserveSyncRequest);
            queryApplyTripStandardResponse.setEnable(true);
            BigDecimal maxPrice = priceRuleVO.getMaxPrice();

            StandardAmountSyncRequest standardAmountSyncRequest = new StandardAmountSyncRequest();
            standardAmountSyncRequest.setPriceUpperLimit(maxPrice);
            standardAmountSyncRequest.setControlType(String.join(",", priceRuleVO.getRejectTypes()));
            queryApplyTripStandardResponse.setStandardAmount(standardAmountSyncRequest);
        } else if(reserveRuleVO != null && reserveRuleVO.getReserves() != null){
            queryApplyTripStandardResponse.setUnLimitedType("Reserve");
            List<StandardReserveTypeSyncRequest> reserveTypeList = reserveRuleVO.getReserves().entrySet().stream().map(t->{
                StandardReserveTypeSyncRequest standardReserveTypeSyncRequest = new StandardReserveTypeSyncRequest();
                standardReserveTypeSyncRequest.setReserveCode(t.getKey());
                standardReserveTypeSyncRequest.setReserveName(t.getValue());
                return standardReserveTypeSyncRequest;
            }).collect(Collectors.toList());
            StandardReserveSyncRequest reserveSyncRequest = new StandardReserveSyncRequest();
            reserveSyncRequest.setReserveTypeList(reserveTypeList);
            reserveSyncRequest.setControlType(String.join(",",reserveRuleVO.getRejectTypes()));
            queryApplyTripStandardResponse.setEnable(true);
            queryApplyTripStandardResponse.setStandardReserve(reserveSyncRequest);

        } else {
            queryApplyTripStandardResponse.setUnLimitedType("Amount");
            BigDecimal maxPrice = priceRuleVO.getMaxPrice();
            StandardAmountSyncRequest reserveSyncRequest = new StandardAmountSyncRequest();
            reserveSyncRequest.setPriceUpperLimit(maxPrice);
            reserveSyncRequest.setControlType(String.join(",", priceRuleVO.getRejectTypes()));
            queryApplyTripStandardResponse.setStandardAmount(reserveSyncRequest);
        }
        return queryApplyTripStandardResponse;
    }

    /**
     * 通过token查询差标
     */
    public FlightTravelStandardSoaVo getTravelStandardByToken(String token) {
        GetTravelStandardByTokenRequest request = new GetTravelStandardByTokenRequest();
        request.setTokenList(Collections.singletonList(token));
        List<TravelStandardResponse> travelStandardResponseList = managementClientUtil.getTravelStandardByToken(request);
        if (CollectionUtils.isEmpty(travelStandardResponseList)){
            log.warn("查询差标失败:token" + token);
            throw new RuntimeException("获取差标异常");
        }
        travelStandardResponseList = travelStandardResponseList.stream().filter(t->t.getTravelStandardToken().getOwnerType() == TravelStandardOwnerTypeEnum.REQUEST.getCode()).collect(Collectors.toList());
        List<TravelStandardRuleVO> ruleList = travelStandardResponseList.stream().findFirst().map(TravelStandardResponse::getRuleChain).map(RuleChainVO::getRuleList).orElse(null);
        if(ruleList == null){
            ruleList = Collections.emptyList();
        }
        AdvanceRuleVO advanceRuleVO = (AdvanceRuleVO) ruleList.stream().filter(t -> "AdvanceRule".equals(t.getName())).findFirst().orElse(null);
        FlightTravelStandardSoaVo flightTravelStandardSoaVo = new FlightTravelStandardSoaVo();
        // todo flightTravelStandardSoaVo.setOrgId(travelStandardResponseList.get(0).getRuleChain().get);
        flightTravelStandardSoaVo.setProductSwitch(travelStandardResponseList.get(0).getRuleChain().getBookable() ? "E" : "N");
        FlightTravelStandardSoaVo.AdvancedBookVo advancedBookVo = new FlightTravelStandardSoaVo.AdvancedBookVo();
        advancedBookVo.setStatus(SwitchEnum.N.getCode());
        if (advanceRuleVO != null){
            advancedBookVo.setStatus(SwitchEnum.E.getCode());
            if (advanceRuleVO.getRejectTypes() != null && advanceRuleVO.getRejectTypes().length > 0){
                advancedBookVo.setBookRcSet(String.join(",",advanceRuleVO.getRejectTypes()));
            }
            advancedBookVo.setAdvancedBookDays(advanceRuleVO.getAdvanceDays());
            advancedBookVo.setBookRcCheckList(getRCInfo(advanceRuleVO.getExceedReasonList()));
        }
        flightTravelStandardSoaVo.setAdvancedBookVo(advancedBookVo);
        ClassDiscountRuleVO classDiscountRuleVO = (ClassDiscountRuleVO) ruleList.stream().filter(t -> "ClassDiscountRule".equals(t.getName())).findFirst().orElse(null);
        FlightTravelStandardSoaVo.ClassDiscountVo classDiscountVo = new FlightTravelStandardSoaVo.ClassDiscountVo();
        classDiscountVo.setClassDiscountChoose(SwitchEnum.N.getCode());
        if (classDiscountRuleVO != null){
            boolean isClazzControl = "舱等控制".equals(classDiscountRuleVO.getDesc());
            classDiscountVo.setClassCode(null);
            if(isClazzControl){
                classDiscountVo.setClassDiscountChoose(FlightSwitchEnum.ClassDiscountSwitch.C.getCode());
                classDiscountVo.setDiscountNum(classDiscountRuleVO.getDiscount());
                if (classDiscountRuleVO.getRejectTypes() != null && classDiscountRuleVO.getRejectTypes().length > 0){
                    classDiscountVo.setClassDiscountRcSet(String.join(",", classDiscountRuleVO.getRejectTypes()));
                }
                List<FlightTravelStandardSoaVo.ClassShielded> classShieldedList = Conditional.ofEmptyAble(classDiscountRuleVO.getShieldedClazzList()).map(t->t.stream().map(o->{
                    FlightTravelStandardSoaVo.ClassShielded classShielded = new FlightTravelStandardSoaVo.ClassShielded();
                    classShielded.setClassCode(o);
                    classShielded.setClassName(ClazzEnum.getEnumByCode(o).getName());
                    return classShielded;
                }).collect(Collectors.toList())).orElse(Collections.emptyList());
                classDiscountVo.setClassShieldedList(classShieldedList);
                List<FlightTravelStandardSoaVo.ClassCheck> classCheckList = Conditional.ofEmptyAble(classDiscountRuleVO.getClazzInfoList()).map(t->t.stream().map(o->{
                    FlightTravelStandardSoaVo.ClassCheck classShielded = new FlightTravelStandardSoaVo.ClassCheck();
                    classShielded.setClassCode(o.getFlightClass());
                    classShielded.setClassName(ClazzEnum.getEnumByCode(o.getFlightClass()).getName());
                    classShielded.setDurationNum(o.getDurationNum());
                    classShielded.setDurationType(o.getDurationType());
                    return classShielded;
                }).collect(Collectors.toList())).orElse(Collections.emptyList());
                classDiscountVo.setClassCheckList(classCheckList);
                classDiscountVo.setClassDiscountRcList(getRCInfo(classDiscountRuleVO.getExceedReasonList()));
            }else {
                String clazzCode = Conditional.ofNullable(classDiscountRuleVO.getClazzInfoList()).map(t -> t.get(0))
                        .map(ClazzVo::getFlightClass).orElseThrow(()-> new CorpBusinessException(OrganizationResponseCodeEnum.CLAZZ_INFO_EMPTY));
                classDiscountVo.setClassCode(clazzCode);
                classDiscountVo.setClassName(ClazzEnum.getEnumByCode(clazzCode).getName());
                classDiscountVo.setDiscountNum(classDiscountRuleVO.getDiscount());
                if (classDiscountRuleVO.getRejectTypes() != null && classDiscountRuleVO.getRejectTypes().length > 0){
                    classDiscountVo.setClassDiscountRcSet(String.join(",", classDiscountRuleVO.getRejectTypes()));
                }
            }
            flightTravelStandardSoaVo.setClassDiscountVo(classDiscountVo);
        }


        DistanceRuleVO distanceRuleVO = (DistanceRuleVO) ruleList.stream().filter(t -> "DistanceRule".equals(t.getName())).findFirst().orElse(null);
        FlightTravelStandardSoaVo.MileageVo mileageVo = new FlightTravelStandardSoaVo.MileageVo();
        mileageVo.setStatus(SwitchEnum.N.getCode());
        if (distanceRuleVO != null){
            mileageVo.setStatus(SwitchEnum.E.getCode());
            if (distanceRuleVO.getRejectTypes() != null && distanceRuleVO.getRejectTypes().length > 0){
                mileageVo.setMileageRcSet(String.join(",", distanceRuleVO.getRejectTypes()));
            }
            mileageVo.setMileageNumber(distanceRuleVO.getMinKilometer());
            mileageVo.setMileageRcCheckList(getRCInfo(distanceRuleVO.getExceedReasonList()));
        }
        flightTravelStandardSoaVo.setMileageVo(mileageVo);

        LowPriceRuleVO lowPriceRuleVO = (LowPriceRuleVO) ruleList.stream().filter(t -> "LowPriceRule".equals(t.getName())).findFirst().orElse(null);
        FlightTravelStandardSoaVo.LowpriceVo lowpriceVo = new FlightTravelStandardSoaVo.LowpriceVo();
        lowpriceVo.setLowpriceSwitch(SwitchEnum.N.getCode());
        if (lowPriceRuleVO != null){
            lowpriceVo.setLowpriceSwitch(SwitchEnum.E.getCode());
            if (lowPriceRuleVO.getRejectTypes() != null && lowPriceRuleVO.getRejectTypes().length > 0){
                lowpriceVo.setLowpriceControlType(String.join(",", lowPriceRuleVO.getRejectTypes()));
            }
            lowpriceVo.setLowpriceCompareTimeEnd(lowPriceRuleVO.getPriceEndTime());
            lowpriceVo.setLowpriceCompareTimeStart(lowPriceRuleVO.getPriceStartTime());
            lowpriceVo.setLowpriceFloatAmount(Null.or(lowPriceRuleVO.getFloatValue(), BigDecimal::intValue));
            lowpriceVo.setLowpriceFloatType(lowPriceRuleVO.getFloatType());
            lowpriceVo.setLowPriceDomAirTicketTimeOptionsHour((int) (lowPriceRuleVO.getCompareInMinutes() / 60));
            lowpriceVo.setLowPriceDomAirTicketTimeOptionsMinutes((int) (lowPriceRuleVO.getCompareInMinutes() % 60));
            lowpriceVo.setAirportComparePrice(lowPriceRuleVO.getAirportFilter() ? "T" : "F");
            lowpriceVo.setLowpriceFloatType(lowPriceRuleVO.getFloatType());
            lowpriceVo.setLowpriceFloatNum("B".equals(lowPriceRuleVO.getFloatType()) ? lowPriceRuleVO.getFloatValue().intValue() : 0);
            lowpriceVo.setLowpriceFloatAmount("B".equals(lowPriceRuleVO.getFloatType()) ? 0 : lowPriceRuleVO.getFloatValue().intValue());
            lowpriceVo.setTransferNeedComparePrice(lowPriceRuleVO.getTransferCompare() ? "T" : "F");
            lowpriceVo.setLowpriceVoRcList(getRCInfo(lowPriceRuleVO.getExceedReasonList()));
        }
        flightTravelStandardSoaVo.setLowpriceVo(lowpriceVo);

        AmountRuleVO amountRuleVO = (AmountRuleVO) ruleList.stream().filter(t -> "AmountRule".equals(t.getName())).findFirst().orElse(null);
        FlightTravelStandardSoaVo.FlightAmountControlVo flightAmountControlVo = new FlightTravelStandardSoaVo.FlightAmountControlVo();
        flightAmountControlVo.setStatus(SwitchEnum.N.getCode());
        if (amountRuleVO != null){
            flightAmountControlVo.setStatus(SwitchEnum.E.getCode());
            if (amountRuleVO.getRejectTypes() != null && amountRuleVO.getRejectTypes().length > 0){
                flightAmountControlVo.setAmountRcSet(String.join(",", amountRuleVO.getRejectTypes()));
            }
            flightAmountControlVo.setAmountControlNum(amountRuleVO.getAmountControlNum());
            flightAmountControlVo.setAmountRcCheckList(getRCInfo(amountRuleVO.getExceedReasonList()));
        }
        flightTravelStandardSoaVo.setAmountControlVo(flightAmountControlVo);

        ProtocolPriceRuleVO protocolPriceRuleVO = (ProtocolPriceRuleVO) ruleList.stream().filter(t -> "ProtocolPriceRule".equals(t.getName())).findFirst().orElse(null);
        ProtocolPriceControl protocolPriceControl = new ProtocolPriceControl();
        protocolPriceControl.setStatus(SwitchEnum.N.getCode());
        if (protocolPriceRuleVO != null){
            protocolPriceControl.setStatus(SwitchEnum.E.getCode());
            protocolPriceControl.setProtocolPriceRcCheckList(getRCInfo(protocolPriceRuleVO.getExceedReasonList()));
            if (protocolPriceRuleVO.getRejectTypes() != null && protocolPriceRuleVO.getRejectTypes().length > 0){
                protocolPriceControl.setProtocolPriceRcSet(String.join(",", protocolPriceRuleVO.getRejectTypes()));
            }
        }
        flightTravelStandardSoaVo.setProtocolPrice(protocolPriceControl);

        List<ForbidTimeRuleVO> forbidTimeRuleVOList = ruleList.stream()
                .filter(t -> "ForbidTimeRule".equals(t.getName()))
                .map(t-> (ForbidTimeRuleVO)t)
                .collect(Collectors.toList());
        FlightTravelStandardSoaVo.TimeVo timeVo = new FlightTravelStandardSoaVo.TimeVo();
        timeVo.setStatus(SwitchEnum.N.getCode());
        if (CollectionUtils.isNotEmpty(forbidTimeRuleVOList)){
            timeVo.setStatus(SwitchEnum.E.getCode());
            List<ExceedReasonVO> exceedReasonVOList =
                    forbidTimeRuleVOList.stream().map(TravelStandardRuleVO::getExceedReasonList).flatMap(Collection::stream).collect(Collectors.toList());
            if (forbidTimeRuleVOList.get(0).getRejectTypes() != null && forbidTimeRuleVOList.get(0).getRejectTypes().length > 0){
                timeVo.setTimeRcSet(String.join(",", forbidTimeRuleVOList.get(0).getRejectTypes()));
            }
            timeVo.setMbTravelstandFlightTimeVos(forbidTimeRuleVOList.stream().map(t->{
                MbTravelstandFlightTimeVo mbTravelstandFlightTimeVo = new MbTravelstandFlightTimeVo();
                Date endTime = null;
                Date startTime = null;
                try {
                    endTime = DateUtils.parseDate(t.getEndTime(), "HH:mm");
                    startTime = DateUtils.parseDate(t.getStartTime(), "HH:mm");
                } catch (ParseException e) {
                    log.error("解析日期失败：{}", t.getEndTime());
                }
                mbTravelstandFlightTimeVo.setEndTime(endTime);
                mbTravelstandFlightTimeVo.setStartTime(startTime);
                mbTravelstandFlightTimeVo.setWeek(t.getWeekDay());
                return mbTravelstandFlightTimeVo;
            }).collect(Collectors.toList()));
            timeVo.setTimeRcCheckList(getRCInfo(exceedReasonVOList));
        }
        flightTravelStandardSoaVo.setTimeVo(timeVo);
        return flightTravelStandardSoaVo;
    }

    private List<Node> getRCInfo(List<ExceedReasonVO> reasonVOList){
        if(CollectionUtils.isEmpty(reasonVOList)){
            return Collections.emptyList();
        }
        return reasonVOList.stream().map(t -> {
            Node node = new Node();
            node.setId(String.valueOf(t.getId()));
            node.setIsChecked(true);
            node.setName(t.getName());
            return node;
        }).collect(Collectors.toList());
    }
}
